Set-up packages // libraries and prepare for data import:
library(psych)
library(likert)
library(tidyverse)
library(jsonlite)
library(ggplot2)
library(mosaic)
source("http://pcwww.liv.ac.uk/~william/R/crosstab.r")
theme_set(theme_classic())
Set-up directories, import and clean data:
rm(list=ls())
setwd("/Users/allieblaising/desktop/bang/R")
getwd()
[1] "/Users/allieblaising/Desktop/bang/R"
dataPath = "../.data"
## Define function to extract survey results:
extractSurvey = function(frame,survey) {
rounds = seq(1,length(frame$results.format[[1]]))
roundResponses = lapply(rounds, function(round) {
getCol = paste("results.",survey,".",round, sep="")
surveyCols = Filter(function(x) grepl(getCol,x),names(frame))
newCols = lapply(surveyCols, function(x) gsub(getCol,paste("results.",survey, sep=""),x) )
surveyFrame = frame[,surveyCols]
if (is.null(newCols)) {return("No newCols")}
names(surveyFrame) = newCols
surveyFrame$id = frame$id
surveyFrame$round = round
surveyFrame$batch = frame$batch
surveyFrame$rooms = frame$rooms
surveyFrame$manipulation = frame$results.manipulationCheck
surveyFrame$blacklist = frame$results.blacklistCheck
return(surveyFrame)
})
return(Reduce(rbind,roundResponses))
}
#Find directory for import (be sure to verify that batch #s align from bangData import and imports below):
batches = dir(dataPath, pattern = "^[0-9]+$" )
completeBatches = Filter(function(batch) {
if (any(dir(paste(dataPath,batch,sep="/")) == "batch.json") && (any(dir(paste(dataPath,batch,sep="/")) == "users.json")) ) {
batchData = read_json(paste(dataPath,batch,"batch.json",sep="/"), simplifyVector = TRUE)
return(any(batchData$batchComplete == TRUE))
}
return(FALSE)
}, batches)
userFiles = lapply(completeBatches, function(batch) {
userFile = read_json(paste(dataPath,batch,"users.json",sep="/"), simplifyVector = TRUE)
return(flatten(userFile, recursive = TRUE))
})
## Retroactively find rooms from chat data:
overlappingFiles = Reduce(function(x,y) merge(x, y, all=TRUE), userFiles)
roundsWithRooms = apply(overlappingFiles,1,function(x) {
roomsForIndividual = lapply(seq(1,3),function(y) {
x$room = x$rooms[y]
x$round = y
return(x)
})
return(Reduce(rbind,roomsForIndividual))
})
More cleaning before visualizations:
## Apply extract survey function to extract the right columns and rows for viability survey:
survey = 'viabilityCheck'
frame <- extractSurvey(overlappingFiles, survey)
## Reduce to vertically combine rows in roundwithRooms list:
finalRounds = as.data.frame(Reduce(rbind,roundsWithRooms))
## Subset incomplete cases from viability survey dataframe:
## MSB: complete.cases doesn't work when there aren't NAs, but empty lists, alternatives rather than subsetting where
## blacklist is empty? Doens't work: test <- complete.cases(data)
data <- frame[frame$manipulation!="",]
## Rename room to rooms so that both are retained in future merge:
data <- rename(data, rooms = "rooms")
## Subset incomplete cases for final rounds dataframe:
data2 <- finalRounds[finalRounds$results.manipulationCheck!="", ]
## Select only variables of interest from final rounds:
data2 = data2 %>% select(id, batch, room, bonus, name, friends,
friends_history, results.condition, results.format,
results.manipulation,results.manipulationCheck,results.blacklistCheck, round)
## Convert to compatible data types before merge (this should be simplified)
data2$batch <- unlist(data2$batch)
data$batch <- unlist(data$batch)
data2$round <- unlist(data2$round)
data2$id <- unlist(data2$id)
## Before merge, data and data2 should ahve the same # of observations
## Merge columns by id, round and batch #s:
data <- left_join(data, data2, by=NULL)
Joining, by = c("id", "round", "batch")
## Subset only observations with batch #s in complete batches
allConditions <- data[data$batch %in% completeBatches, ]
Conditionally assign conditions based on treatment and results column:
## Messy, but robust? Verify, verify, verify.
data <- data %>% mutate(
condition = case_when(
results.condition=='treatment' & results.format=="c(1, 2, 1)" & round==1 ~ "A",
results.condition=='treatment' & results.format=="c(1, 2, 1)" & round==2 ~ "B",
results.condition=='treatment' & results.format=="c(1, 2, 1)" & round==3 ~ "Ap",
results.condition=='treatment' & results.format=="c(1, 1, 2)" & round==1 ~ "A",
results.condition=='treatment' & results.format=="c(1, 1, 2)" & round==2 ~ "Ap",
results.condition=='treatment' & results.format=="c(1, 1, 2)" & round==3 ~ "B",
results.condition=='treatment' & results.format=="c(2, 1, 1)" & round==1 ~ "B",
results.condition=='treatment' & results.format=="c(2, 1, 1)" & round==2 ~ "A",
results.condition=='treatment' & results.format=="c(2, 1, 1)" & round==3 ~ "Ap" ,
results.condition=='control' & results.format=="c(1, 2, 1)" & round==1 ~ "A",
results.condition=='control' & results.format=="c(1, 2, 1)" & round==2 ~ "B",
results.condition=='control' & results.format=="c(1, 2, 1)" & round==3 ~ "Ap",
results.condition=='control' & results.format=="c(1, 1, 2)" & round==1 ~ "A",
results.condition=='control' & results.format=="c(1, 1, 2)" & round==2 ~ "Ap",
results.condition=='control' & results.format=="c(1, 1, 2)" & round==3 ~ "B",
results.condition=='control' & results.format=="c(2, 1, 1)" & round==1 ~ "B",
results.condition=='control' & results.format=="c(2, 1, 1)" & round==2 ~ "A",
results.condition=='control' & results.format=="c(2, 1, 1)" & round==3 ~ "Ap" ,
results.condition=='baseline' & results.format=="c(1, 2, 3)" & round==1 ~ "A" ,
results.condition=='baseline' & results.format=="c(1, 2, 3)" & round==2 ~ "B" ,
results.condition=='baseline' & results.format=="c(1, 2, 3)" & round==3 ~ "C"
))
Set-up for factors for viability questions:
data <- rename(data, "repeatTeam" = results.viabilityCheck.15)
## Remove observations where viability survey wasn't on (remove this line if we want to keep observations with viability off):
data <- na.omit(data)
levels <- c("Strongly Disagree", "Disagree", "Neutral","Agree", "Strongly Agree")
clean <- data %>%
mutate_at(.vars = vars(contains("results.viabilityCheck")), funs(factor(., levels = levels)))
## Viabilitylikert visuals:
## Subset only viabilitySurvey columns and condition column (condition column used to visualize likert responses for conditions)
viabilityLikert <- select(clean, contains("results.viabilityCheck"), "condition", "results.condition")
viabilityLabels = c("1. The members of this team could work for a long time together"
, "2. Most of the members of this team would welcome the opportunity to work as a group again in the future." ,
"3. This team has the capacity for long-term success.",
"4. This team has what it takes to be effective in the future.",
"5. This team would work well together in the future." ,
" 6. This team has positioned itself well for continued success.",
" 7. This team has the ability to perform well in the future. ",
" 8. This team has the ability to function as an ongoing unit." ,
" 9. This team should continue to function as a unit. ",
" 10. This team has the resources to perform well in the future. ",
" 11. This team is well positioned for growth over time. ",
" 12. This team can develop to meet future challenges. ",
" 13. This team has the capacity to sustain itself. ",
" 14. This team has what it takes to endure in future performance episodes.", "condition", "results.condition")
names(viabilityLikert) <- rep(viabilityLabels)
Likert visualizations:
## Likert graph for all viability responses across all conditions (i.e. baseline, control and treatment):
likert.out <- likert(viabilityLikert[-c(15:16)])
plot(likert.out)

## Subset A and Ap (i.e. A prime) responses for treatment group:
# Treatment + A:
treatmentA <- viabilityLikert %>% filter(condition=="A" & results.condition=="treatment")
likert.treatmentA <- likert(treatmentA[-c(15:16)])
plot(likert.treatmentA)

# Treatment + Ap:
treatmentAp <- viabilityLikert %>% filter(condition=="Ap" & results.condition=="treatment")
likert.treatmentAp <- likert(treatmentAp[-c(15:16)])
plot(likert.treatmentAp)

# Treatment + B:
treatmentB <- viabilityLikert %>% filter(condition=="B" & results.condition=="treatment")
likert.treatmentB <- likert(treatmentB[-c(15:16)])
plot(likert.treatmentAp)

## Customize code above to filter on other conditions and treatments of interest.
Exploratory data analysis part #1:
## Create a new dataframe that converts factors to numeric for statistical analyses:
stats <- clean %>% mutate_if(is.factor, as.numeric)
for (i in 1:nrow(stats)) {
stats$sum[i] <- sum(stats[i,1:14])
}
stats$median <- median(stats$sum)
stats$mean <- mean(stats$sum)
## Revalue repeat team: keep plyr b/c some weird R stuff requires library to be called directly (recode values to )
stats$repeatTeam <- plyr::revalue(stats$repeatTeam, c("Yes"="0", "No"="1"))
stats$repeatTeam <- plyr::revalue(stats$repeatTeam, c("Keep this team"="0", "Do not keep this team"="1"))
## Convert to compatible classes for team grouping:
stats$repeatTeam <- as.numeric(stats$repeatTeam)
stats$results.condition <- unlist(stats$results.condition)
stats$results.format <- as.character(stats$results.format)
stats$room <- unlist(stats$room)
## Dplyr to group teams and summarise variables for each group: group_by to find teams and summarise to compact individual results into group level results (i.e. one row of variable results per team)
groupedProportion <- stats %>%
group_by(room, batch, round, condition, results.condition, results.format) %>%
summarise(n=n(), mean=mean(sum), median=median(sum),prop=sum(repeatTeam)/n) %>%
## Filter out all teams with n=1 (i.e. a person in a chat room alone)
filter(n>1)
## Individual proportion:
individualProportion <- stats %>% group_by(round, batch, room) %>%
mutate(sum=sum, mean=mean(sum), median=median(sum), n=n(),prop=sum(repeatTeam)/n) %>% filter(n>1)
## Table showing how many teams we've run in each condition combination:
table(groupedProportion$condition, groupedProportion$results.condition)
control treatment
A 18 37
Ap 18 37
B 19 35
Exploratory data analysis part #2:
## Plot of prop and mean per team with standard error:
ggplot(groupedProportion, aes(x=prop, y=mean)) +
geom_point() +
stat_smooth(method = "lm", col = "red") +
labs(subtitle="",
x="Proportion of answers to Q15: ",
y="Numeric sum of viability measures questions (range: 7-70)") + facet_grid(condition ~ results.format)

## Unlist for condition for graph:
groupedProportion$results.condition <- unlist(groupedProportion$results.condition)
## Team viability sum and Q15 factor repeat team answers facet_grid by condition, results.condition and results.format (all users)
g <- ggplot(stats, aes(factor(repeatTeam), sum))
g + geom_boxplot(varwidth=T, fill="plum") +
labs(subtitle="Sum of viability measures grouped by repeat team question:",
x="Distribution of responses to Q15: ",
y="Numeric sum of viability measures questions (range: 7-70)") + facet_grid(condition ~ results.format)

## Team viability mean and repeat team answers facet_grid by results.condition, condition and results.format
g <- ggplot(stats, aes(factor(repeatTeam), mean))
g + geom_boxplot(varwidth=T, fill="plum") +
labs(subtitle="Individual mean of viability measures grouped fracture measure score across all conditions",
x="Distribution of responses to Q15",
y="Numeric sum of viability measures questions (range: 7-70)") + facet_grid(condition ~ results.format)

g <- ggplot(stats, aes(factor(repeatTeam), sum))
g + geom_boxplot(varwidth=T, fill="plum") +
labs(subtitle="Individual fracture score vs. mean viability:",
x="",
y="Numeric sum of viability measures questions (range: 7-70)") + facet_grid(condition ~ results.condition)

## groupedProportion: anlaysis on team level
ggplot(groupedProportion, aes(x=prop, y=mean)) +
geom_point() +
stat_smooth(method = "lm", col = "red") + labs(title="Team fracture proportion vs. team mean viability")

## Mean vs. median plot for viability sums per team:
ggplot(groupedProportion, aes(x=mean, y=median)) +
geom_point() +
stat_smooth(method = "lm", col = "red") + labs(main="Scatterplot of median vs. mean for team viability sums")

ggplot(data=groupedProportion, aes(groupedProportion$prop)) +
geom_histogram(breaks=seq(0, 1, by=0.20),
col="red",
fill="green",
alpha=.2) + labs(title="Count of team proportions of fracture value responses",
x="", y="Count") + facet_grid(condition ~ results.format)

Probability of fracture across teams and condition combinations:
tally(~fracture| condition, data = conditionalPropTreatment, format = "proportion")
condition
fracture A Ap
0 0.5405405 0.6756757
1 0.4594595 0.3243243
Boxplot for fracture scores vs. viability score sum (7-70)
groupedProportionFracture$fracture <- as.numeric(groupedProportionFracture$fracture)
g <- ggplot(groupedProportionFracture, aes(factor(fracture), median))
g + geom_boxplot(varwidth=T, fill="plum") +
labs(subtitle="Team median viability score in relation to binary fracture value",
x="Binary fracture value",
y="Numeric sum of viability measures questions (range: 7-70)") + scale_x_discrete(labels=c("0" = "No Fracture", "1" = "Fracture")) + facet_grid(condition ~ results.condition)

Fracture proportion scatterplots:
## LEARNING EFFECT
## Overall fracture change:
sum(ifelse(fractureLE1$fracture==fractureLE2$fracture,0,1))
longer object length is not a multiple of shorter object length
[1] 27
Absolute change in fracture proportions between conditions:
Histogram comparisons of fracture ratios across treatment, control and learning effect conditions
ggplot(data=groupedProportionFractureTreatment, aes(fracture)) +
geom_bar(breaks=seq(0, 1, by=0.20),
col="red",
fill="green",
alpha=.2) + labs(title="Fracture ratios: treatment condition") + facet_grid(condition ~ results.condition)
Ignoring unknown parameters: breaks

Graphs for mean distrbution per treatment condition:
Chat data:
g <- ggplot(chatFreqStats, aes(n)) + scale_fill_brewer(palette = "Spectral")
g + geom_histogram(aes(fill=factor(round)),
bins=5,
col="black",
size=.1) + # change number of bins
labs(title="Histogram of chat line length per team (includes teams with n=1)",
fill = "Round") +
xlab(label="Number of lines from chat data per team") +
ylab(label="Count") + facet_grid(fracture1~fracture2)
Error: At least one layer must contain all faceting variables: `fracture1`.
* Plot is missing `fracture1`
* Layer 1 is missing `fracture1`

Conditional probabilities:
# Print out the probabilities
round(c(p1, p2, p3, p4), digits = 2)
[1] 0.56 0.44 0.71 0.29
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgU2V0LXVwIHBhY2thZ2VzIC8vIGxpYnJhcmllcyBhbmQgcHJlcGFyZSBmb3IgZGF0YSBpbXBvcnQ6IApgYGB7cn0KIyMgVW5jb21tZW50IGluc3RhbGwucGFja2FnZXMgYW5kIHJ1biBvdXRzaWRlIG9mIG5vdGVib29rIGVudmlyb25tZW50OiAKIyMgaW5zdGFsbC5wYWNrYWdlcyhjKCJwc3ljaCIgLCJ4dGFibGUiLCAidGlkeXZlcnNlIiwgImpzb25saXRlIiwgImxpa2VydCIsICJnZ3Bsb3QyIiwgInBsb3R5IiwgIm1vc2FpYyIpKQoKbGlicmFyeShwc3ljaCkKbGlicmFyeShsaWtlcnQpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobW9zYWljKQpsaWJyYXJ5KHBsb3RseSkKc291cmNlKCJodHRwOi8vcGN3d3cubGl2LmFjLnVrL353aWxsaWFtL1IvY3Jvc3N0YWIuciIpCnRoZW1lX3NldCh0aGVtZV9jbGFzc2ljKCkpCmBgYAoKIyMgU2V0LXVwIGRpcmVjdG9yaWVzLCBpbXBvcnQgYW5kIGNsZWFuIGRhdGE6IApgYGB7cn0Kcm0obGlzdD1scygpKQpzZXR3ZCgiL1VzZXJzL2FsbGllYmxhaXNpbmcvZGVza3RvcC9iYW5nL1IiKSAKZ2V0d2QoKQpkYXRhUGF0aCA9ICIuLi8uZGF0YSIKIyMgRGVmaW5lIGZ1bmN0aW9uIHRvIGV4dHJhY3Qgc3VydmV5IHJlc3VsdHM6IApleHRyYWN0U3VydmV5ID0gZnVuY3Rpb24oZnJhbWUsc3VydmV5KSB7CiAgcm91bmRzID0gc2VxKDEsbGVuZ3RoKGZyYW1lJHJlc3VsdHMuZm9ybWF0W1sxXV0pKQogIHJvdW5kUmVzcG9uc2VzID0gbGFwcGx5KHJvdW5kcywgZnVuY3Rpb24ocm91bmQpIHsKICAgIGdldENvbCA9IHBhc3RlKCJyZXN1bHRzLiIsc3VydmV5LCIuIixyb3VuZCwgc2VwPSIiKQogICAgc3VydmV5Q29scyA9IEZpbHRlcihmdW5jdGlvbih4KSBncmVwbChnZXRDb2wseCksbmFtZXMoZnJhbWUpKQogICAgbmV3Q29scyA9IGxhcHBseShzdXJ2ZXlDb2xzLCBmdW5jdGlvbih4KSBnc3ViKGdldENvbCxwYXN0ZSgicmVzdWx0cy4iLHN1cnZleSwgc2VwPSIiKSx4KSApCiAgICBzdXJ2ZXlGcmFtZSA9IGZyYW1lWyxzdXJ2ZXlDb2xzXQogICAgaWYgKGlzLm51bGwobmV3Q29scykpIHtyZXR1cm4oIk5vIG5ld0NvbHMiKX0KICAgIG5hbWVzKHN1cnZleUZyYW1lKSA9IG5ld0NvbHMKICAgIHN1cnZleUZyYW1lJGlkID0gZnJhbWUkaWQKICAgIHN1cnZleUZyYW1lJHJvdW5kID0gcm91bmQKICAgIHN1cnZleUZyYW1lJGJhdGNoID0gZnJhbWUkYmF0Y2gKICAgIHN1cnZleUZyYW1lJHJvb21zID0gZnJhbWUkcm9vbXMKICAgIHN1cnZleUZyYW1lJG1hbmlwdWxhdGlvbiA9IGZyYW1lJHJlc3VsdHMubWFuaXB1bGF0aW9uQ2hlY2sKICAgIHN1cnZleUZyYW1lJGJsYWNrbGlzdCA9IGZyYW1lJHJlc3VsdHMuYmxhY2tsaXN0Q2hlY2sKICAgIHJldHVybihzdXJ2ZXlGcmFtZSkKICB9KQogIHJldHVybihSZWR1Y2UocmJpbmQscm91bmRSZXNwb25zZXMpKQp9CiNGaW5kIGRpcmVjdG9yeSBmb3IgaW1wb3J0IChiZSBzdXJlIHRvIHZlcmlmeSB0aGF0IGJhdGNoICNzIGFsaWduIGZyb20gYmFuZ0RhdGEgaW1wb3J0IGFuZCBpbXBvcnRzIGJlbG93KTogCmJhdGNoZXMgPSBkaXIoZGF0YVBhdGgsIHBhdHRlcm4gPSAiXlswLTldKyQiICkKY29tcGxldGVCYXRjaGVzID0gRmlsdGVyKGZ1bmN0aW9uKGJhdGNoKSB7IAogIGlmIChhbnkoZGlyKHBhc3RlKGRhdGFQYXRoLGJhdGNoLHNlcD0iLyIpKSA9PSAiYmF0Y2guanNvbiIpICYmIChhbnkoZGlyKHBhc3RlKGRhdGFQYXRoLGJhdGNoLHNlcD0iLyIpKSA9PSAidXNlcnMuanNvbiIpKSApIHsKICAgIGJhdGNoRGF0YSA9IHJlYWRfanNvbihwYXN0ZShkYXRhUGF0aCxiYXRjaCwiYmF0Y2guanNvbiIsc2VwPSIvIiksIHNpbXBsaWZ5VmVjdG9yID0gVFJVRSkKICAgIHJldHVybihhbnkoYmF0Y2hEYXRhJGJhdGNoQ29tcGxldGUgPT0gVFJVRSkpCiAgfSAKICByZXR1cm4oRkFMU0UpCn0sIGJhdGNoZXMpCnVzZXJGaWxlcyA9IGxhcHBseShjb21wbGV0ZUJhdGNoZXMsIGZ1bmN0aW9uKGJhdGNoKSB7CiAgdXNlckZpbGUgPSByZWFkX2pzb24ocGFzdGUoZGF0YVBhdGgsYmF0Y2gsInVzZXJzLmpzb24iLHNlcD0iLyIpLCBzaW1wbGlmeVZlY3RvciA9IFRSVUUpCiAgcmV0dXJuKGZsYXR0ZW4odXNlckZpbGUsIHJlY3Vyc2l2ZSA9IFRSVUUpKQp9KQojIyBSZXRyb2FjdGl2ZWx5IGZpbmQgcm9vbXMgZnJvbSBjaGF0IGRhdGE6IApvdmVybGFwcGluZ0ZpbGVzID0gUmVkdWNlKGZ1bmN0aW9uKHgseSkgbWVyZ2UoeCwgeSwgYWxsPVRSVUUpLCB1c2VyRmlsZXMpCnJvdW5kc1dpdGhSb29tcyA9IGFwcGx5KG92ZXJsYXBwaW5nRmlsZXMsMSxmdW5jdGlvbih4KSB7CiAgcm9vbXNGb3JJbmRpdmlkdWFsID0gbGFwcGx5KHNlcSgxLDMpLGZ1bmN0aW9uKHkpIHsKICAgIHgkcm9vbSA9IHgkcm9vbXNbeV0KICAgIHgkcm91bmQgPSB5CiAgICByZXR1cm4oeCkKICB9KQogIHJldHVybihSZWR1Y2UocmJpbmQscm9vbXNGb3JJbmRpdmlkdWFsKSkKfSkKYGBgCgojIyBNb3JlIGNsZWFuaW5nIGJlZm9yZSB2aXN1YWxpemF0aW9uczogCmBgYHtyfQojIyBBcHBseSBleHRyYWN0IHN1cnZleSBmdW5jdGlvbiB0byBleHRyYWN0IHRoZSByaWdodCBjb2x1bW5zIGFuZCByb3dzIGZvciB2aWFiaWxpdHkgc3VydmV5OiAKc3VydmV5ID0gJ3ZpYWJpbGl0eUNoZWNrJwpmcmFtZSA8LSBleHRyYWN0U3VydmV5KG92ZXJsYXBwaW5nRmlsZXMsIHN1cnZleSkKIyMgUmVkdWNlIHRvIHZlcnRpY2FsbHkgY29tYmluZSByb3dzIGluIHJvdW5kd2l0aFJvb21zIGxpc3Q6ICAKZmluYWxSb3VuZHMgPSBhcy5kYXRhLmZyYW1lKFJlZHVjZShyYmluZCxyb3VuZHNXaXRoUm9vbXMpKQojIyBTdWJzZXQgaW5jb21wbGV0ZSBjYXNlcyBmcm9tIHZpYWJpbGl0eSBzdXJ2ZXkgZGF0YWZyYW1lOiAKIyMgTVNCOiBjb21wbGV0ZS5jYXNlcyBkb2Vzbid0IHdvcmsgd2hlbiB0aGVyZSBhcmVuJ3QgTkFzLCBidXQgZW1wdHkgbGlzdHMsIGFsdGVybmF0aXZlcyByYXRoZXIgdGhhbiBzdWJzZXR0aW5nIHdoZXJlIAojIyBibGFja2xpc3QgaXMgZW1wdHk/IERvZW5zJ3Qgd29yazogdGVzdCA8LSBjb21wbGV0ZS5jYXNlcyhkYXRhKQpkYXRhIDwtIGZyYW1lW2ZyYW1lJG1hbmlwdWxhdGlvbiE9IiIsXQojIyBSZW5hbWUgcm9vbSB0byByb29tcyBzbyB0aGF0IGJvdGggYXJlIHJldGFpbmVkIGluIGZ1dHVyZSBtZXJnZTogCmRhdGEgPC0gcmVuYW1lKGRhdGEsIHJvb21zID0gInJvb21zIikKIyMgU3Vic2V0IGluY29tcGxldGUgY2FzZXMgZm9yIGZpbmFsIHJvdW5kcyBkYXRhZnJhbWU6IApkYXRhMiA8LSBmaW5hbFJvdW5kc1tmaW5hbFJvdW5kcyRyZXN1bHRzLm1hbmlwdWxhdGlvbkNoZWNrIT0iIiwgXQojIyBTZWxlY3Qgb25seSB2YXJpYWJsZXMgb2YgaW50ZXJlc3QgZnJvbSBmaW5hbCByb3VuZHM6IApkYXRhMiA9IGRhdGEyICU+JSBzZWxlY3QoaWQsIGJhdGNoLCByb29tLCBib251cywgbmFtZSwgZnJpZW5kcywgCiAgICAgICAgICAgICAgICAgICAgICAgICBmcmllbmRzX2hpc3RvcnksIHJlc3VsdHMuY29uZGl0aW9uLCByZXN1bHRzLmZvcm1hdCwKICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMubWFuaXB1bGF0aW9uLHJlc3VsdHMubWFuaXB1bGF0aW9uQ2hlY2sscmVzdWx0cy5ibGFja2xpc3RDaGVjaywgcm91bmQpCiMjIENvbnZlcnQgdG8gY29tcGF0aWJsZSBkYXRhIHR5cGVzIGJlZm9yZSBtZXJnZSAodGhpcyBzaG91bGQgYmUgc2ltcGxpZmllZCkKZGF0YTIkYmF0Y2ggPC0gdW5saXN0KGRhdGEyJGJhdGNoKQpkYXRhJGJhdGNoIDwtIHVubGlzdChkYXRhJGJhdGNoKQpkYXRhMiRyb3VuZCA8LSB1bmxpc3QoZGF0YTIkcm91bmQpCmRhdGEyJGlkIDwtIHVubGlzdChkYXRhMiRpZCkKIyMgQmVmb3JlIG1lcmdlLCBkYXRhIGFuZCBkYXRhMiBzaG91bGQgYWh2ZSB0aGUgc2FtZSAjIG9mIG9ic2VydmF0aW9ucwojIyBNZXJnZSBjb2x1bW5zIGJ5IGlkLCByb3VuZCBhbmQgYmF0Y2ggI3M6IApkYXRhIDwtIGxlZnRfam9pbihkYXRhLCBkYXRhMiwgYnk9TlVMTCkKIyMgU3Vic2V0IG9ubHkgb2JzZXJ2YXRpb25zIHdpdGggYmF0Y2ggI3MgaW4gY29tcGxldGUgYmF0Y2hlcyAKYWxsQ29uZGl0aW9ucyA8LSBkYXRhW2RhdGEkYmF0Y2ggJWluJSBjb21wbGV0ZUJhdGNoZXMsIF0KYGBgCiMjIENvbmRpdGlvbmFsbHkgYXNzaWduIGNvbmRpdGlvbnMgYmFzZWQgb24gdHJlYXRtZW50IGFuZCByZXN1bHRzIGNvbHVtbjogCmBgYHtyfQojIyBNZXNzeSwgYnV0IHJvYnVzdD8gVmVyaWZ5LCB2ZXJpZnksIHZlcmlmeS4gIApkYXRhIDwtIGRhdGEgJT4lIG11dGF0ZSgKICBjb25kaXRpb24gPSBjYXNlX3doZW4oCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J3RyZWF0bWVudCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMiwgMSkiICYgcm91bmQ9PTEgfiAiQSIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSd0cmVhdG1lbnQnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDIsIDEpIiAmIHJvdW5kPT0yIH4gIkIiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0ndHJlYXRtZW50JyAmIHJlc3VsdHMuZm9ybWF0PT0iYygxLCAyLCAxKSIgJiByb3VuZD09MyB+ICJBcCIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSd0cmVhdG1lbnQnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDEsIDIpIiAmIHJvdW5kPT0xIH4gIkEiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0ndHJlYXRtZW50JyAmIHJlc3VsdHMuZm9ybWF0PT0iYygxLCAxLCAyKSIgJiByb3VuZD09MiB+ICJBcCIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSd0cmVhdG1lbnQnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDEsIDIpIiAmIHJvdW5kPT0zIH4gIkIiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0ndHJlYXRtZW50JyAmIHJlc3VsdHMuZm9ybWF0PT0iYygyLCAxLCAxKSIgJiByb3VuZD09MSB+ICJCIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J3RyZWF0bWVudCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMiwgMSwgMSkiICYgcm91bmQ9PTIgfiAiQSIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSd0cmVhdG1lbnQnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDIsIDEsIDEpIiAmIHJvdW5kPT0zIH4gIkFwIiAsCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2NvbnRyb2wnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDIsIDEpIiAmIHJvdW5kPT0xIH4gIkEiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0nY29udHJvbCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMiwgMSkiICYgcm91bmQ9PTIgfiAiQiIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSdjb250cm9sJyAmIHJlc3VsdHMuZm9ybWF0PT0iYygxLCAyLCAxKSIgJiByb3VuZD09MyB+ICJBcCIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSdjb250cm9sJyAmIHJlc3VsdHMuZm9ybWF0PT0iYygxLCAxLCAyKSIgJiByb3VuZD09MSB+ICJBIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2NvbnRyb2wnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDEsIDIpIiAmIHJvdW5kPT0yIH4gIkFwIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2NvbnRyb2wnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDEsIDEsIDIpIiAmIHJvdW5kPT0zIH4gIkIiLCAKICAgIHJlc3VsdHMuY29uZGl0aW9uPT0nY29udHJvbCcgJiByZXN1bHRzLmZvcm1hdD09ImMoMiwgMSwgMSkiICYgcm91bmQ9PTEgfiAiQiIsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSdjb250cm9sJyAmIHJlc3VsdHMuZm9ybWF0PT0iYygyLCAxLCAxKSIgJiByb3VuZD09MiB+ICJBIiwgCiAgICByZXN1bHRzLmNvbmRpdGlvbj09J2NvbnRyb2wnICYgcmVzdWx0cy5mb3JtYXQ9PSJjKDIsIDEsIDEpIiAmIHJvdW5kPT0zIH4gIkFwIiAsIAogICAgcmVzdWx0cy5jb25kaXRpb249PSdiYXNlbGluZScgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMiwgMykiICYgcm91bmQ9PTEgfiAiQSIgLAogICAgcmVzdWx0cy5jb25kaXRpb249PSdiYXNlbGluZScgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMiwgMykiICYgcm91bmQ9PTIgfiAiQiIgLAogICAgcmVzdWx0cy5jb25kaXRpb249PSdiYXNlbGluZScgJiByZXN1bHRzLmZvcm1hdD09ImMoMSwgMiwgMykiICYgcm91bmQ9PTMgfiAiQyIgCiAgKSkgCmBgYAoKIyMgU2V0LXVwIGZvciBmYWN0b3JzIGZvciB2aWFiaWxpdHkgcXVlc3Rpb25zOiAKYGBge3J9CmRhdGEgPC0gcmVuYW1lKGRhdGEsICJyZXBlYXRUZWFtIiA9IHJlc3VsdHMudmlhYmlsaXR5Q2hlY2suMTUpCiMjIFJlbW92ZSBvYnNlcnZhdGlvbnMgd2hlcmUgdmlhYmlsaXR5IHN1cnZleSB3YXNuJ3Qgb24gKHJlbW92ZSB0aGlzIGxpbmUgaWYgd2Ugd2FudCB0byBrZWVwIG9ic2VydmF0aW9ucyB3aXRoIHZpYWJpbGl0eSBvZmYpOiAKZGF0YSA8LSBuYS5vbWl0KGRhdGEpCmxldmVscyA8LSBjKCJTdHJvbmdseSBEaXNhZ3JlZSIsICJEaXNhZ3JlZSIsICJOZXV0cmFsIiwiQWdyZWUiLCAiU3Ryb25nbHkgQWdyZWUiKSAKY2xlYW4gPC0gZGF0YSAlPiUgCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhjb250YWlucygicmVzdWx0cy52aWFiaWxpdHlDaGVjayIpKSwgZnVucyhmYWN0b3IoLiwgbGV2ZWxzID0gbGV2ZWxzKSkpIAojIyBWaWFiaWxpdHlsaWtlcnQgdmlzdWFsczogCiMjIFN1YnNldCBvbmx5IHZpYWJpbGl0eVN1cnZleSBjb2x1bW5zIGFuZCBjb25kaXRpb24gY29sdW1uIChjb25kaXRpb24gY29sdW1uIHVzZWQgdG8gdmlzdWFsaXplIGxpa2VydCByZXNwb25zZXMgZm9yIGNvbmRpdGlvbnMpCnZpYWJpbGl0eUxpa2VydCA8LSBzZWxlY3QoY2xlYW4sIGNvbnRhaW5zKCJyZXN1bHRzLnZpYWJpbGl0eUNoZWNrIiksICJjb25kaXRpb24iLCAicmVzdWx0cy5jb25kaXRpb24iKQp2aWFiaWxpdHlMYWJlbHMgPSBjKCIxLiBUaGUgbWVtYmVycyBvZiB0aGlzIHRlYW0gY291bGQgd29yayBmb3IgYSBsb25nIHRpbWUgdG9nZXRoZXIiIAogICAgICAgICAgICAgICAgICAgICwgIjIuIE1vc3Qgb2YgdGhlIG1lbWJlcnMgb2YgdGhpcyB0ZWFtIHdvdWxkIHdlbGNvbWUgdGhlIG9wcG9ydHVuaXR5IHRvIHdvcmsgYXMgYSBncm91cCBhZ2FpbiBpbiB0aGUgZnV0dXJlLiIgLCAKICAgICAgICAgICAgICAgICAgICAiMy4gVGhpcyB0ZWFtIGhhcyB0aGUgY2FwYWNpdHkgZm9yIGxvbmctdGVybSBzdWNjZXNzLiIsIAogICAgICAgICAgICAgICAgICAgICI0LiBUaGlzIHRlYW0gaGFzIHdoYXQgaXQgdGFrZXMgdG8gYmUgZWZmZWN0aXZlIGluIHRoZSBmdXR1cmUuIiwgCiAgICAgICAgICAgICAgICAgICAgIjUuIFRoaXMgdGVhbSB3b3VsZCB3b3JrIHdlbGwgdG9nZXRoZXIgaW4gdGhlIGZ1dHVyZS4iICwgCiAgICAgICAgICAgICAgICAgICAgIiA2LiBUaGlzIHRlYW0gaGFzIHBvc2l0aW9uZWQgaXRzZWxmIHdlbGwgZm9yIGNvbnRpbnVlZCBzdWNjZXNzLiIsICAKICAgICAgICAgICAgICAgICAgICAiIDcuIFRoaXMgdGVhbSBoYXMgdGhlIGFiaWxpdHkgdG8gcGVyZm9ybSB3ZWxsIGluIHRoZSBmdXR1cmUuICIsIAogICAgICAgICAgICAgICAgICAgICIgOC4gVGhpcyB0ZWFtIGhhcyB0aGUgYWJpbGl0eSB0byBmdW5jdGlvbiBhcyBhbiBvbmdvaW5nIHVuaXQuIiAsIAogICAgICAgICAgICAgICAgICAgICIgOS4gVGhpcyB0ZWFtIHNob3VsZCBjb250aW51ZSB0byBmdW5jdGlvbiBhcyBhIHVuaXQuICIsIAogICAgICAgICAgICAgICAgICAgICIgMTAuIFRoaXMgdGVhbSBoYXMgdGhlIHJlc291cmNlcyB0byBwZXJmb3JtIHdlbGwgaW4gdGhlIGZ1dHVyZS4gIiwgCiAgICAgICAgICAgICAgICAgICAgIiAxMS4gVGhpcyB0ZWFtIGlzIHdlbGwgcG9zaXRpb25lZCBmb3IgZ3Jvd3RoIG92ZXIgdGltZS4gIiwgCiAgICAgICAgICAgICAgICAgICAgIiAxMi4gVGhpcyB0ZWFtIGNhbiBkZXZlbG9wIHRvIG1lZXQgZnV0dXJlIGNoYWxsZW5nZXMuICIsIAogICAgICAgICAgICAgICAgICAgICIgMTMuIFRoaXMgdGVhbSBoYXMgdGhlIGNhcGFjaXR5IHRvIHN1c3RhaW4gaXRzZWxmLiAiLCAKICAgICAgICAgICAgICAgICAgICAiIDE0LiBUaGlzIHRlYW0gaGFzIHdoYXQgaXQgdGFrZXMgdG8gZW5kdXJlIGluIGZ1dHVyZSBwZXJmb3JtYW5jZSBlcGlzb2Rlcy4iLCAiY29uZGl0aW9uIiwgInJlc3VsdHMuY29uZGl0aW9uIikgCm5hbWVzKHZpYWJpbGl0eUxpa2VydCkgPC0gcmVwKHZpYWJpbGl0eUxhYmVscykgCmBgYAoKIyMgTGlrZXJ0IHZpc3VhbGl6YXRpb25zOiAKYGBge3J9CiMjIExpa2VydCBncmFwaCBmb3IgYWxsIHZpYWJpbGl0eSByZXNwb25zZXMgYWNyb3NzIGFsbCBjb25kaXRpb25zIChpLmUuIGJhc2VsaW5lLCBjb250cm9sIGFuZCB0cmVhdG1lbnQpOiAKbGlrZXJ0Lm91dCA8LSBsaWtlcnQodmlhYmlsaXR5TGlrZXJ0Wy1jKDE1OjE2KV0pIApwbG90KGxpa2VydC5vdXQpCiMjIFN1YnNldCBBIGFuZCBBcCAoaS5lLiBBIHByaW1lKSByZXNwb25zZXMgZm9yIHRyZWF0bWVudCBncm91cDogCiMgVHJlYXRtZW50ICsgQTogCnRyZWF0bWVudEEgPC0gdmlhYmlsaXR5TGlrZXJ0ICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iQSIgJiByZXN1bHRzLmNvbmRpdGlvbj09InRyZWF0bWVudCIpIApsaWtlcnQudHJlYXRtZW50QSA8LSBsaWtlcnQodHJlYXRtZW50QVstYygxNToxNildKQpwbG90KGxpa2VydC50cmVhdG1lbnRBKQojIFRyZWF0bWVudCArIEFwOiAKdHJlYXRtZW50QXAgPC0gdmlhYmlsaXR5TGlrZXJ0ICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iQXAiICYgcmVzdWx0cy5jb25kaXRpb249PSJ0cmVhdG1lbnQiKSAKbGlrZXJ0LnRyZWF0bWVudEFwIDwtIGxpa2VydCh0cmVhdG1lbnRBcFstYygxNToxNildKQpwbG90KGxpa2VydC50cmVhdG1lbnRBcCkKIyBUcmVhdG1lbnQgKyBCOiAKdHJlYXRtZW50QiA8LSB2aWFiaWxpdHlMaWtlcnQgJT4lIGZpbHRlcihjb25kaXRpb249PSJCIiAmIHJlc3VsdHMuY29uZGl0aW9uPT0idHJlYXRtZW50IikgCmxpa2VydC50cmVhdG1lbnRCIDwtIGxpa2VydCh0cmVhdG1lbnRCWy1jKDE1OjE2KV0pCnBsb3QobGlrZXJ0LnRyZWF0bWVudEFwKQojIyBDdXN0b21pemUgY29kZSBhYm92ZSB0byBmaWx0ZXIgb24gb3RoZXIgY29uZGl0aW9ucyBhbmQgdHJlYXRtZW50cyBvZiBpbnRlcmVzdC4gCmBgYAoKIyMgRXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyBwYXJ0ICMxOiAKYGBge3J9CiMjIENyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgdGhhdCBjb252ZXJ0cyBmYWN0b3JzIHRvIG51bWVyaWMgZm9yIHN0YXRpc3RpY2FsIGFuYWx5c2VzOiAKc3RhdHMgPC0gY2xlYW4gJT4lIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLm51bWVyaWMpCmZvciAoaSBpbiAxOm5yb3coc3RhdHMpKSB7CiAgc3RhdHMkc3VtW2ldIDwtIHN1bShzdGF0c1tpLDE6MTRdKSAgICAgICAgICAgICAgICAgICAgICAgICAgCn0gCnN0YXRzJG1lZGlhbiA8LSBtZWRpYW4oc3RhdHMkc3VtKQpzdGF0cyRtZWFuIDwtIG1lYW4oc3RhdHMkc3VtKQojIyBSZXZhbHVlIHJlcGVhdCB0ZWFtOiBrZWVwIHBseXIgYi9jIHNvbWUgd2VpcmQgUiBzdHVmZiByZXF1aXJlcyBsaWJyYXJ5IHRvIGJlIGNhbGxlZCBkaXJlY3RseSAocmVjb2RlIHZhbHVlcyB0byApCnN0YXRzJHJlcGVhdFRlYW0gPC0gcGx5cjo6cmV2YWx1ZShzdGF0cyRyZXBlYXRUZWFtLCBjKCJZZXMiPSIwIiwgIk5vIj0iMSIpKQpzdGF0cyRyZXBlYXRUZWFtIDwtIHBseXI6OnJldmFsdWUoc3RhdHMkcmVwZWF0VGVhbSwgYygiS2VlcCB0aGlzIHRlYW0iPSIwIiwgIkRvIG5vdCBrZWVwIHRoaXMgdGVhbSI9IjEiKSkKIyMgQ29udmVydCB0byBjb21wYXRpYmxlIGNsYXNzZXMgZm9yIHRlYW0gZ3JvdXBpbmc6IApzdGF0cyRyZXBlYXRUZWFtIDwtIGFzLm51bWVyaWMoc3RhdHMkcmVwZWF0VGVhbSkKc3RhdHMkcmVzdWx0cy5jb25kaXRpb24gPC0gdW5saXN0KHN0YXRzJHJlc3VsdHMuY29uZGl0aW9uKQpzdGF0cyRyZXN1bHRzLmZvcm1hdCA8LSBhcy5jaGFyYWN0ZXIoc3RhdHMkcmVzdWx0cy5mb3JtYXQpCnN0YXRzJHJvb20gPC0gdW5saXN0KHN0YXRzJHJvb20pCiMjIERwbHlyIHRvIGdyb3VwIHRlYW1zIGFuZCBzdW1tYXJpc2UgdmFyaWFibGVzIGZvciBlYWNoIGdyb3VwOiBncm91cF9ieSB0byBmaW5kIHRlYW1zIGFuZCBzdW1tYXJpc2UgdG8gY29tcGFjdCBpbmRpdmlkdWFsIHJlc3VsdHMgaW50byBncm91cCBsZXZlbCByZXN1bHRzIChpLmUuIG9uZSByb3cgb2YgdmFyaWFibGUgcmVzdWx0cyBwZXIgdGVhbSkKZ3JvdXBlZFByb3BvcnRpb24gPC0gc3RhdHMgJT4lCiAgZ3JvdXBfYnkocm9vbSwgYmF0Y2gsIHJvdW5kLCBjb25kaXRpb24sIHJlc3VsdHMuY29uZGl0aW9uLCByZXN1bHRzLmZvcm1hdCkgJT4lIAogIHN1bW1hcmlzZShuPW4oKSwgbWVhbj1tZWFuKHN1bSksIG1lZGlhbj1tZWRpYW4oc3VtKSxwcm9wPXN1bShyZXBlYXRUZWFtKS9uKSAlPiUgCiMjIEZpbHRlciBvdXQgYWxsIHRlYW1zIHdpdGggbj0xIChpLmUuIGEgcGVyc29uIGluIGEgY2hhdCByb29tIGFsb25lKQogIGZpbHRlcihuPjEpCiMjIEluZGl2aWR1YWwgcHJvcG9ydGlvbjogCmluZGl2aWR1YWxQcm9wb3J0aW9uIDwtIHN0YXRzICU+JSBncm91cF9ieShyb3VuZCwgYmF0Y2gsIHJvb20pICU+JSAKICBtdXRhdGUoc3VtPXN1bSwgbWVhbj1tZWFuKHN1bSksIG1lZGlhbj1tZWRpYW4oc3VtKSwgbj1uKCkscHJvcD1zdW0ocmVwZWF0VGVhbSkvbikgJT4lIGZpbHRlcihuPjEpCgojIyBUYWJsZSBzaG93aW5nIGhvdyBtYW55IHRlYW1zIHdlJ3ZlIHJ1biBpbiBlYWNoIGNvbmRpdGlvbiBjb21iaW5hdGlvbjogIAp0YWJsZShncm91cGVkUHJvcG9ydGlvbiRjb25kaXRpb24sIGdyb3VwZWRQcm9wb3J0aW9uJHJlc3VsdHMuY29uZGl0aW9uKQpgYGAKCiMjIEV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgcGFydCAjMjogCmBgYHtyfQojIyBQbG90IG9mIHByb3AgYW5kIG1lYW4gcGVyIHRlYW0gd2l0aCBzdGFuZGFyZCBlcnJvcjogCmdncGxvdChncm91cGVkUHJvcG9ydGlvbiwgYWVzKHg9cHJvcCwgeT1tZWFuKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJyZWQiKSArIAogIGxhYnMoc3VidGl0bGU9IiIsIAogICAgICAgeD0iUHJvcG9ydGlvbiBvZiBhbnN3ZXJzIHRvIFExNTogIiwKICAgICAgIHk9Ik51bWVyaWMgc3VtIG9mIHZpYWJpbGl0eSBtZWFzdXJlcyBxdWVzdGlvbnMgKHJhbmdlOiA3LTcwKSIpICsgZmFjZXRfZ3JpZChjb25kaXRpb24gfiByZXN1bHRzLmZvcm1hdCkKCiMjIFVubGlzdCBmb3IgY29uZGl0aW9uIGZvciBncmFwaDogCmdyb3VwZWRQcm9wb3J0aW9uJHJlc3VsdHMuY29uZGl0aW9uIDwtIHVubGlzdChncm91cGVkUHJvcG9ydGlvbiRyZXN1bHRzLmNvbmRpdGlvbikKIyMgVGVhbSB2aWFiaWxpdHkgc3VtIGFuZCBRMTUgZmFjdG9yIHJlcGVhdCB0ZWFtIGFuc3dlcnMgZmFjZXRfZ3JpZCBieSBjb25kaXRpb24sIHJlc3VsdHMuY29uZGl0aW9uIGFuZCByZXN1bHRzLmZvcm1hdCAoYWxsIHVzZXJzKSAKZyA8LSBnZ3Bsb3Qoc3RhdHMsIGFlcyhmYWN0b3IocmVwZWF0VGVhbSksIHN1bSkpCmcgKyBnZW9tX2JveHBsb3QodmFyd2lkdGg9VCwgZmlsbD0icGx1bSIpICsgCiAgbGFicyhzdWJ0aXRsZT0iU3VtIG9mIHZpYWJpbGl0eSBtZWFzdXJlcyBncm91cGVkIGJ5IHJlcGVhdCB0ZWFtIHF1ZXN0aW9uOiIsIAogICAgICAgeD0iRGlzdHJpYnV0aW9uIG9mIHJlc3BvbnNlcyB0byBRMTU6ICIsCiAgICAgICB5PSJOdW1lcmljIHN1bSBvZiB2aWFiaWxpdHkgbWVhc3VyZXMgcXVlc3Rpb25zIChyYW5nZTogNy03MCkiKSArIGZhY2V0X2dyaWQoY29uZGl0aW9uIH4gcmVzdWx0cy5mb3JtYXQpCgpnIDwtIGdncGxvdChzdGF0cywgYWVzKGZhY3RvcihyZXBlYXRUZWFtKSwgc3VtKSkKZyArIGdlb21fYm94cGxvdCh2YXJ3aWR0aD1ULCBmaWxsPSJwbHVtIikgKyAKICBsYWJzKHN1YnRpdGxlPSJJbmRpdmlkdWFsIGZyYWN0dXJlIHNjb3JlIHZzLiBtZWFuIHZpYWJpbGl0eToiLCAKICAgICAgIHg9IiIsCiAgICAgICB5PSJOdW1lcmljIHN1bSBvZiB2aWFiaWxpdHkgbWVhc3VyZXMgcXVlc3Rpb25zIChyYW5nZTogNy03MCkiKSArIGZhY2V0X2dyaWQoY29uZGl0aW9uIH4gcmVzdWx0cy5jb25kaXRpb24pCgojIyBncm91cGVkUHJvcG9ydGlvbjogYW5sYXlzaXMgb24gdGVhbSBsZXZlbCAKCmdncGxvdChncm91cGVkUHJvcG9ydGlvbiwgYWVzKHg9cHJvcCwgeT1tZWFuKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJyZWQiKSArIGxhYnModGl0bGU9IlRlYW0gZnJhY3R1cmUgcHJvcG9ydGlvbiB2cy4gdGVhbSBtZWFuIHZpYWJpbGl0eSIpIAoKIyMgTWVhbiB2cy4gbWVkaWFuIHBsb3QgZm9yIHZpYWJpbGl0eSBzdW1zIHBlciB0ZWFtOiAKZ2dwbG90KGdyb3VwZWRQcm9wb3J0aW9uLCBhZXMoeD1tZWFuLCB5PW1lZGlhbikpICsgCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAicmVkIikgKyBsYWJzKG1haW49IlNjYXR0ZXJwbG90IG9mIG1lZGlhbiB2cy4gbWVhbiBmb3IgdGVhbSB2aWFiaWxpdHkgc3VtcyIpCgpnZ3Bsb3QoZGF0YT1ncm91cGVkUHJvcG9ydGlvbiwgYWVzKGdyb3VwZWRQcm9wb3J0aW9uJHByb3ApKSArIAogIGdlb21faGlzdG9ncmFtKGJyZWFrcz1zZXEoMCwgMSwgYnk9MC4yMCksIAogICAgICAgICAgICAgICAgIGNvbD0icmVkIiwgCiAgICAgICAgICAgICAgICAgZmlsbD0iZ3JlZW4iLCAKICAgICAgICAgICAgICAgICBhbHBoYT0uMikgKyBsYWJzKHRpdGxlPSJDb3VudCBvZiB0ZWFtIHByb3BvcnRpb25zIG9mIGZyYWN0dXJlIHZhbHVlIHJlc3BvbnNlcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD0iIiwgeT0iQ291bnQiKSArIGZhY2V0X2dyaWQoY29uZGl0aW9uIH4gcmVzdWx0cy5mb3JtYXQpCmBgYAoKIyMgUHJvYmFiaWxpdHkgb2YgZnJhY3R1cmUgYWNyb3NzIHRlYW1zIGFuZCBjb25kaXRpb24gY29tYmluYXRpb25zOiAKYGBge3J9CiMjIERlZmluZSBhbmQgaW5pdGlhbGl6ZSBjdXQtb2ZmIHBvaW50IGZvciBmcmFjdHVyZTogCmdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUgPC0gZ3JvdXBlZFByb3BvcnRpb24gJT4lCiAgZ3JvdXBfYnkocmVzdWx0cy5jb25kaXRpb24sIGNvbmRpdGlvbikgJT4lIAogIG11dGF0ZShmcmFjdHVyZSA9IGNhc2Vfd2hlbiAocHJvcDwuNTAgfiAiMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3A+PS41MH4gIjEiKSkKCiMjIFByb2JhYmlsaXR5IG9mIGZyYWN0dXJlIGdpdmVuIGNvbmRpdGlvbiBpbiB0cmVhdG1lbnQ6IApjb25kaXRpb25hbFByb3BUcmVhdG1lbnQgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVRyZWF0bWVudCAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IkEiIHwgY29uZGl0aW9uPT0iQXAiKQp0YWxseSh+ZnJhY3R1cmUgfCBjb25kaXRpb24sIGRhdGEgPSBjb25kaXRpb25hbFByb3BUcmVhdG1lbnQsIGZvcm1hdCA9ICJwcm9wb3J0aW9uIikKYGBgCgojIyBCb3hwbG90IGZvciBmcmFjdHVyZSBzY29yZXMgdnMuIHZpYWJpbGl0eSBzY29yZSBzdW0gKDctNzApCmBgYHtyfQpncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlJGZyYWN0dXJlIDwtIGFzLm51bWVyaWMoZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZSRmcmFjdHVyZSkKZyA8LSBnZ3Bsb3QoZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZSwgYWVzKGZhY3RvcihmcmFjdHVyZSksIG1lZGlhbikpCmcgKyBnZW9tX2JveHBsb3QodmFyd2lkdGg9VCwgZmlsbD0icGx1bSIpICsgCiAgbGFicyhzdWJ0aXRsZT0iVGVhbSBtZWRpYW4gdmlhYmlsaXR5IHNjb3JlIGluIHJlbGF0aW9uIHRvIGJpbmFyeSBmcmFjdHVyZSB2YWx1ZSIsIAogICAgICAgeD0iQmluYXJ5IGZyYWN0dXJlIHZhbHVlIiwKICAgICAgIHk9Ik51bWVyaWMgc3VtIG9mIHZpYWJpbGl0eSBtZWFzdXJlcyBxdWVzdGlvbnMgKHJhbmdlOiA3LTcwKSIpICsgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiMCIgPSAiTm8gRnJhY3R1cmUiLCAiMSIgPSAiRnJhY3R1cmUiKSkgKyBmYWNldF9ncmlkKGNvbmRpdGlvbiB+IHJlc3VsdHMuY29uZGl0aW9uKQoKYGBgCgoKIyMgRnJhY3R1cmUgcHJvcG9ydGlvbiBzY2F0dGVycGxvdHM6IApgYGB7cn0KIyMgTGVhcm5pbmcgZWZmZWN0IC8vIGJhc2VsaW5lOiAKIyMgTWFrZSBuZXcgZGF0YSB0aGF0IGluY2x1ZGVzIHRlYW1zIHdpdGggZGlmZmVyZW50IHJvdW5kIDEgYW5kIHJvdW5kIDMgdGVhbXM6IApncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlTEUgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZSAlPiUgZmlsdGVyKHJlc3VsdHMuZm9ybWF0PT0iYygxLCAxLCAyKSIgfCByZXN1bHRzLmZvcm1hdD09ImMoMiwgMSwgMSkiICYgcm91bmQ9PSIxIiB8IHJvdW5kPT0iMyIpIAoKZnJhY3R1cmVMRTEgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZUxFICU+JSBmaWx0ZXIocm91bmQ9PSIxIikKZnJhY3R1cmVMRTIgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZUxFICU+JSBmaWx0ZXIocm91bmQ9PSIzIikKZnJhY3R1cmVMRSA8LSBjYmluZChmcmFjdHVyZUxFMSwgZnJhY3R1cmVMRTIpCgojIyBUcmVhdG1lbnQ6IApncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlVHJlYXRtZW50IDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUgJT4lIApmaWx0ZXIocmVzdWx0cy5jb25kaXRpb249PSJ0cmVhdG1lbnQiKQp0cmVhdG1lbnRGcmFjdHVyZTEgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVRyZWF0bWVudCAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IkEiKQp0cmVhdG1lbnRGcmFjdHVyZTIgPC0gZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVRyZWF0bWVudCAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IkFwIikKdHJlYXRtZW50RnJhY3R1cmUgPC0gY2JpbmQodHJlYXRtZW50RnJhY3R1cmUxLCB0cmVhdG1lbnRGcmFjdHVyZTIpCgojIyBDb250cm9sOiAgCmdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVDb250cm9sIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmUgJT4lIAogIGZpbHRlcihyZXN1bHRzLmNvbmRpdGlvbj09ImNvbnRyb2wiKSAKY29udHJvbEZyYWN0dXJlMSA8LSBncm91cGVkUHJvcG9ydGlvbkZyYWN0dXJlQ29udHJvbCAlPiUgZmlsdGVyKGNvbmRpdGlvbj09IkEiKQpjb250cm9sRnJhY3R1cmUyIDwtIGdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVDb250cm9sICU+JSBmaWx0ZXIoY29uZGl0aW9uPT0iQXAiKQpjb250cm9sRnJhY3R1cmUgPC0gY2JpbmQoY29udHJvbEZyYWN0dXJlMSwgY29udHJvbEZyYWN0dXJlMikKCmdncGxvdChjb250cm9sRnJhY3R1cmUsIGFlcyhwcm9wLCBwcm9wMSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21faml0dGVyKCkgKyBjb29yZF9maXhlZCgpICsgeGxpbSgwLjAsMS4wKSArIHlsaW0oMC4wLDEuMCkgKyBsYWJzKHRpdGxlPSJUZWFtIGZyYWN0dXJlIGluIHRoZSBmaXJzdCB2cy4gdGhpcmQgaW4gY29udHJvbCIsIHN1YnRpdGxlPSJObyBmcmFjdHVyZT0wLCBGcmFjdHVyZT0xIiwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHg9IkZyYWN0dXJlIHRoZSBmaXJzdCB0aW1lIGEgdGVhbSBpbnRlcmFjdHMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSJGcmFjdHVyZSB0aGUgc2Vjb25kIHRpbWUgYSB0ZWFtIGludGVyYWN0cywgd2l0aG91dCBrbm93aW5nIGl0IikgCiMjIERlZmluaW5nIGZyYWN0dXJlOiAKCiMjIFRSRUFUTUVOVCBFRkZFQ1Q6IAojIyBPdmVyYWxsIGZyYWN0dXJlIGNoYW5nZTogCnN1bShpZmVsc2UodHJlYXRtZW50RnJhY3R1cmUxJGZyYWN0dXJlPT10cmVhdG1lbnRGcmFjdHVyZTIkZnJhY3R1cmUsMCwxKSkgCiMjIE5vIGZyYWN0dXJlIHRvIGZyYWN0dXJlOiAKc3VtKGlmZWxzZSh0cmVhdG1lbnRGcmFjdHVyZTEkZnJhY3R1cmU9PTAgJiB0cmVhdG1lbnRGcmFjdHVyZTIkZnJhY3R1cmU9PTEsMSwwKSkKIyMgRnJhY3R1cmUgdG8gbm8gZnJhY3R1cmU6IApzdW0oaWZlbHNlKHRyZWF0bWVudEZyYWN0dXJlMSRmcmFjdHVyZT09MSAmIHRyZWF0bWVudEZyYWN0dXJlMiRmcmFjdHVyZT09MCwxLDApKQojIyBDT05UUk9MIEVGRkVDVDogCiMjIE92ZXJhbGwgZnJhY3R1cmUgY2hhbmdlOiAKc3VtKGlmZWxzZShjb250cm9sRnJhY3R1cmUxJGZyYWN0dXJlPT1jb250cm9sRnJhY3R1cmUyJGZyYWN0dXJlLDAsMSkpCiMjIE5vIGZyYWN0dXJlIHRvIGZyYWN0dXJlOiAKc3VtKGlmZWxzZShjb250cm9sRnJhY3R1cmUxJGZyYWN0dXJlPT0wICYgY29udHJvbEZyYWN0dXJlMiRmcmFjdHVyZT09MSwxLDApKQojIyBGcmFjdHVyZSB0byBubyBmcmFjdHVyZTogCnN1bShpZmVsc2UoY29udHJvbEZyYWN0dXJlMSRmcmFjdHVyZT09MSAmIGNvbnRyb2xGcmFjdHVyZTIkZnJhY3R1cmU9PTAsMSwwKSkKIyMgTEVBUk5JTkcgRUZGRUNUIAojIyBPdmVyYWxsIGZyYWN0dXJlIGNoYW5nZTogCnN1bShpZmVsc2UoZnJhY3R1cmVMRTEkZnJhY3R1cmU9PWZyYWN0dXJlTEUyJGZyYWN0dXJlLDAsMSkpIAojIyBObyBmcmFjdHVyZSB0byBmcmFjdHVyZToKc3VtKGlmZWxzZShmcmFjdHVyZUxFMSRmcmFjdHVyZT09MCAmIGZyYWN0dXJlTEUyJGZyYWN0dXJlPT0xLDEsMCkpCiMjIEZyYWN0dXJlIHRvIG5vIGZyYWN0dXJlIApzdW0oaWZlbHNlKGZyYWN0dXJlTEUxJGZyYWN0dXJlPT0xICYgZnJhY3R1cmVMRTIkZnJhY3R1cmU9PTAsMSwwKSkKYGBgCiMjIEFic29sdXRlIGNoYW5nZSBpbiBmcmFjdHVyZSBwcm9wb3J0aW9ucyBiZXR3ZWVuIGNvbmRpdGlvbnM6IApgYGB7cn0KZnJhY3R1cmVMRSRhYnMgPC0gYWJzKGZyYWN0dXJlTEUyJHByb3AtZnJhY3R1cmVMRTEkcHJvcCkKZyA8LSBnZ3Bsb3QoZnJhY3R1cmVMRSwgYWVzKGFicykpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpCmcgKyBnZW9tX2hpc3RvZ3JhbShiaW5zPTcsIAogICAgICAgICAgICAgICAgICAgY29sPSJwaW5rIiwgCiAgICAgICAgICAgICAgICAgICBzaXplPS40KSArIAogIGxhYnModGl0bGU9IkFic29sdXRlIHZhbHVlIG9mIGNoYW5nZSBpbiB0ZWFtIGZyYWN0dXJlIHByb3BvcnRpb25zIGluIGxlYXJuaW5nIGVmZmVjdCBjb25kaXRpb24iLCAKICAgICAgIGZpbGwgPSAiUm91bmQiKSArIAogIHhsYWIobGFiZWw9IkFic29sdXRlIHZhbHVlIG9mIGNoYW5nZSBpbiB0ZWFtIGZyYWN0dXJlIHByb3BvcnRpb25zIGluIGxlYXJuaW5nIGVmZmVjdCBjb25kaXRpb24iKSArIAogIHlsYWIobGFiZWw9IkNvdW50IikgCgp0cmVhdG1lbnRGcmFjdHVyZSRhYnMgPC0gYWJzKHRyZWF0bWVudEZyYWN0dXJlMiRwcm9wLXRyZWF0bWVudEZyYWN0dXJlMSRwcm9wKQpnIDwtIGdncGxvdCh0cmVhdG1lbnRGcmFjdHVyZSwgYWVzKGFicykpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpCmcgKyBnZW9tX2hpc3RvZ3JhbShiaW5zPTcsIAogICAgICAgICAgICAgICAgICAgY29sPSJwaW5rIiwgCiAgICAgICAgICAgICAgICAgICBzaXplPS40KSArIAogIGxhYnModGl0bGU9IkFic29sdXRlIGNoYW5nZSBpbiB0ZWFtIGZyYWN0dXJlIHByb3BvcnRpb25zIGluIHRyZWF0bWVudCBjb25kaXRpb24iLCAKICAgICAgIGZpbGwgPSAiUm91bmQiKSArIAogIHhsYWIobGFiZWw9IkFic29sdXRlIGNoYW5nZSBpbiB0ZWFtIGZyYWN0dXJlIHByb3BvcnRpb25zIGluIHRyZWF0bWVudCBjb25kaXRpb24iKSArIAogIHlsYWIobGFiZWw9IkNvdW50IikgCgpjb250cm9sRnJhY3R1cmUkYWJzIDwtIGFicyhjb250cm9sRnJhY3R1cmUyJHByb3AtY29udHJvbEZyYWN0dXJlMSRwcm9wKQpnIDwtIGdncGxvdChjb250cm9sRnJhY3R1cmUsIGFlcyhhYnMpKSArIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKQpnICsgZ2VvbV9oaXN0b2dyYW0oYmlucz03LCAKICAgICAgICAgICAgICAgICAgIGNvbD0icGluayIsIAogICAgICAgICAgICAgICAgICAgc2l6ZT0uNCkgKyAKICBsYWJzKHRpdGxlPSJBYnNvbHV0ZSBjaGFuZ2UgaW4gdGVhbSBmcmFjdHVyZSBwcm9wb3J0aW9ucyBpbiBjb250cm9sIGNvbmRpdGlvbiIsIAogICAgICAgZmlsbCA9ICJSb3VuZCIpICsgCiAgeGxhYihsYWJlbD0iQWJzb2x1dGUgY2hhbmdlIGluIHRlYW0gZnJhY3R1cmUgcHJvcG9ydGlvbnMgaW4gY29udHJvbCBjb25kaXRpb24iKSArIAogIHlsYWIobGFiZWw9IkNvdW50IikgCgp0cmVhdG1lbnRGcmFjdHVyZUFic1N1bSA8LSBzdW0odHJlYXRtZW50RnJhY3R1cmUkYWJzKSAKY29udHJvbEZyYWN0dXJlQWJzU3VtIDwtIHN1bShjb250cm9sRnJhY3R1cmUkYWJzKQoKZGYxIDwtIGRhdGEuZnJhbWUodHJlYXRtZW50RnJhY3R1cmVBYnNTdW0sIGNvbnRyb2xGcmFjdHVyZUFic1N1bSkgCgpnZ3Bsb3QoZGYxLCBhZXMoeD1jb250cm9sRnJhY3R1cmVBYnNTdW0sIHk9dHJlYXRtZW50RnJhY3R1cmVBYnNTdW0pKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpIAoKZyA8LSBnZ3Bsb3QodGVzdCxhZXMoeCwgeSkpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpCmcgKyBnZW9tX2JhcigpICsgCiAgbGFicyh0aXRsZT0iQWJzb2x1dGUgY2hhbmdlIGluIHRlYW0gZnJhY3R1cmUgcHJvcG9ydGlvbnMgaW4gY29udHJvbCBjb25kaXRpb24iLCAKICAgICAgIGZpbGwgPSAiUm91bmQiKSArIAogIHhsYWIobGFiZWw9IkFic29sdXRlIGNoYW5nZSBpbiB0ZWFtIGZyYWN0dXJlIHByb3BvcnRpb25zIGluIGNvbnRyb2wgY29uZGl0aW9uIikgKyAKICB5bGFiKGxhYmVsPSJDb3VudCIpIAoKZGF0IDwtIGRhdGEuZnJhbWUoY29uZGl0aW9uQ2hhbmdlcyA9IGZhY3RvcihjKCJTdW0gb2YgYWJzb2x1dGUgZnJhY3R1cmUgY2hhbmdlIGluIHRyZWF0bWVudCIsIlN1bSBvZiBhYnNvbHV0ZSBmcmFjdHVyZSBjaGFuZ2UgaW4gY29udHJvbCIpLCBsZXZlbHM9YygiU3VtIG9mIGFic29sdXRlIGZyYWN0dXJlIGNoYW5nZSBpbiB0cmVhdG1lbnQiLCJTdW0gb2YgYWJzb2x1dGUgZnJhY3R1cmUgY2hhbmdlIGluIGNvbnRyb2wiKSksCiAgICBmcmFjdHVyZVByb3BvcnRpb25DaGFuZ2UgPSBjKDEzLjA4MywgMS4xNjYpKQoKcCA8LSBnZ3Bsb3QoZGF0YT1kYXQsIGFlcyh4PWNvbmRpdGlvbkNoYW5nZXMsIHk9ZnJhY3R1cmVQcm9wb3J0aW9uQ2hhbmdlKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKQpwIDwtIGdncGxvdGx5KHApCnAKYGBgCgojIyBIaXN0b2dyYW0gY29tcGFyaXNvbnMgb2YgZnJhY3R1cmUgcmF0aW9zIGFjcm9zcyB0cmVhdG1lbnQsIGNvbnRyb2wgYW5kIGxlYXJuaW5nIGVmZmVjdCBjb25kaXRpb25zCgpgYGB7cn0KZ2dwbG90KGRhdGE9Z3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVRyZWF0bWVudCwgYWVzKGZyYWN0dXJlKSkgKyAKICBnZW9tX2JhcihicmVha3M9c2VxKDAsIDEsIGJ5PTAuMjApLCAKICAgICAgICAgICAgICAgICBjb2w9InJlZCIsIAogICAgICAgICAgICAgICAgIGZpbGw9ImdyZWVuIiwgCiAgICAgICAgICAgICAgICAgYWxwaGE9LjIpICsgbGFicyh0aXRsZT0iRnJhY3R1cmUgcmF0aW9zOiB0cmVhdG1lbnQgY29uZGl0aW9uIikgKyBmYWNldF9ncmlkKGNvbmRpdGlvbiB+IHJlc3VsdHMuY29uZGl0aW9uKQoKZ2dwbG90KGRhdGE9Z3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZUNvbnRyb2wsIGFlcyhmcmFjdHVyZSkpICsgCiAgZ2VvbV9iYXIoYnJlYWtzPXNlcSgwLCAxLCBieT0wLjIwKSwgCiAgICAgICAgICAgICAgICAgY29sPSJyZWQiLCAKICAgICAgICAgICAgICAgICBmaWxsPSJncmVlbiIsIAogICAgICAgICAgICAgICAgIGFscGhhPS4yKSArIGxhYnModGl0bGU9IkZyYWN0dXJlIHJhdGlvczogY29udHJvbCByb3VuZCIpICsgZmFjZXRfZ3JpZChjb25kaXRpb24gfiByZXN1bHRzLmNvbmRpdGlvbikKCmdncGxvdChkYXRhPWdyb3VwZWRQcm9wb3J0aW9uRnJhY3R1cmVMRSwgYWVzKGZyYWN0dXJlKSkgKyAKICBnZW9tX2JhcihicmVha3M9c2VxKDAsIDEsIGJ5PTAuMjApLCAKICAgICAgICAgICAgICAgICBjb2w9InJlZCIsIAogICAgICAgICAgICAgICAgIGZpbGw9ImdyZWVuIiwgCiAgICAgICAgICAgICAgICAgYWxwaGE9LjIpICsgbGFicyh0aXRsZT0iRnJhY3R1cmUgcmF0aW9zOiBsZWFybmluZyBlZmZlY3QgY29uZGl0aW9uIikgKyBmYWNldF9ncmlkKHJlc3VsdHMuY29uZGl0aW9uIH4gcm91bmQpCgpgYGAKCiMjIEdyYXBocyBmb3IgbWVhbiBkaXN0cmJ1dGlvbiBwZXIgdHJlYXRtZW50IGNvbmRpdGlvbjogCgpgYGB7cn0KIyMgTWVhbiB2aWFiaWxpdHkgZGlzdHJpYnV0aW9uIGdyYXBoOiB0cmVhdG1lbnQgY29uZGl0aW9uLCBBIGdyb3VwIApiYXJmaWxsIDwtICIjNDI3MUFFIgpiYXJsaW5lcyA8LSAiIzFGMzU1MiIKIyMgTWVhbiBmb3IgdHJlYXRtZW50IGFuZCBBIGdyb3VwOiAjI2ZpbGwtaW4pIAptZWFuRGlzdHJpYnV0aW9uVHJlYXRtZW50QSA8LSBnZ3Bsb3QodHJlYXRtZW50QVN0YXRzLCBhZXMoeCA9IHN1bSkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uY291bnQuLiksIGJpbndpZHRoID0gNSwKICAgICAgICAgICAgICAgICBjb2xvdXIgPSBiYXJsaW5lcywgZmlsbCA9IGJhcmZpbGwpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJNZWRpYW4gdmlhYmlsaXR5IHN1bSIsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAxMDAsIDIwKSwKICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoMCwgNzApKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiY291bnQiKSArCiAgZ2d0aXRsZSgiRnJlcXVlbmN5IG9mIHN1bSBvZiB2aWFiaWxpdHkgc2NvcmVzOiBOPSMjZmlsbC1pbiIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZT0xLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICIjZDNkM2QzIiksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhbWlseSA9ICJUYWhvbWEiLCBmYWNlID0gImJvbGQiKSwKICAgICAgICB0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlRhaG9tYSIpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChjb2xvdXI9ImJsYWNrIiwgc2l6ZSA9IDkpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvdXI9ImJsYWNrIiwgc2l6ZSA9IDkpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gIyNmaWxsLWluLCBzaXplID0gMSwgY29sb3VyID0gIiNGRjM3MjEiLAogICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKQptZWFuRGlzdHJpYnV0aW9uVHJlYXRtZW50QQoKIyMgTWVhbiB2aWFiaWxpdHkgZGlzdHJpYnV0aW9uIGdyYXBoOiB0cmVhdG1lbnQgY29uZGl0aW9uLCBBcHJpbWUgZ3JvdXAgCiMjIE1lYW4gZm9yIHRyZWF0bWVudCBjb25kaXRpb24sIEFwcmltZSBncm91cDogKGZpbGwtaW4pCm1lYW5EaXN0cmlidXRpb25UcmVhdG1lbnRBcCA8LSBnZ3Bsb3QodHJlYXRtZW50QXBTdGF0cywgYWVzKHggPSBzdW0pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmNvdW50Li4pLCBiaW53aWR0aCA9IDUsCiAgICAgICAgICAgICAgICAgY29sb3VyID0gYmFybGluZXMsIGZpbGwgPSBiYXJmaWxsKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiTWVkaWFuIHZpYWJpbGl0eSBzdW0iLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMTAwLCAyMCksCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cz1jKDAsIDcwKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gImNvdW50IikgKwogIGdndGl0bGUoIkZyZXF1ZW5jeSBvZiBzdW0gb2YgdmlhYmlsaXR5IHNjb3JlczpOPSMjZmlsbC1pbiIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZT0xLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICIjZDNkM2QzIiksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhbWlseSA9ICJUYWhvbWEiLCBmYWNlID0gImJvbGQiKSwKICAgICAgICB0ZXh0PWVsZW1lbnRfdGV4dChmYW1pbHk9IlRhaG9tYSIpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChjb2xvdXI9ImJsYWNrIiwgc2l6ZSA9IDkpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChjb2xvdXI9ImJsYWNrIiwgc2l6ZSA9IDkpKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gIyNmaWxsLWluLCBzaXplID0gMSwgY29sb3VyID0gIiNGRjM3MjEiLAogICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKQptZWFuRGlzdHJpYnV0aW9uVHJlYXRtZW50QXAKCiMjIE1lYW4gdmlhYmlsaXR5IGRpc3RyaWJ1dGlvbiBncmFwaDogdHJlYXRtZW50IGNvbmRpdGlvbiwgQiBncm91cCAKIyMgTWVhbiBmb3IgdHJlYXRtZW50IGNvbmRpdGlvbiwgQiBncm91cDogCmJhcmZpbGwgPC0gIiM0MjcxQUUiCmJhcmxpbmVzIDwtICIjMUYzNTUyIgptZWFuRGlzdHJpYnV0aW9uVHJlYXRtZW50QiA8LSBnZ3Bsb3QodHJlYXRtZW50QlN0YXRzLCBhZXMoeCA9IHN1bSkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uY291bnQuLiksIGJpbndpZHRoID0gNSwKICAgICAgICAgICAgICAgICBjb2xvdXIgPSBiYXJsaW5lcywgZmlsbCA9IGJhcmZpbGwpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJNZWRpYW4gdmlhYmlsaXR5IHN1bSBcbiBhY3Jvc3MgYWxsIHRlYW1zIGluIG1hc2tlZCByb3VuZCIsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCA5OCwgMTQpLAogICAgICAgICAgICAgICAgICAgICBsaW1pdHM9Yyg3LCA3MCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJjb3VudCIpICsKICBnZ3RpdGxlKCJGcmVxdWVuY3kgb2Ygc3VtIG9mIHZpYWJpbGl0eSBzY29yZXM6IG1hc2tlZCBjb25kaXRpb24sIE49IyNmaWxsLWluIikgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShzaXplPTEsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIiNkM2QzZDMiKSwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgZmFtaWx5ID0gIlRhaG9tYSIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHRleHQ9ZWxlbWVudF90ZXh0KGZhbWlseT0iVGFob21hIiksCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGNvbG91cj0iYmxhY2siLCBzaXplID0gOSksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KGNvbG91cj0iYmxhY2siLCBzaXplID0gOSkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAjI2ZpbGwtaW4sIHNpemUgPSAxLCBjb2xvdXIgPSAiI0ZGMzcyMSIsCiAgICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpIAptZWFuRGlzdHJpYnV0aW9uVHJlYXRtZW50QgpgYGAKCiMjIENoYXQgZGF0YTogCmBgYHtyfQpjaGF0RmlsZXMgPSBsYXBwbHkoY29tcGxldGVCYXRjaGVzLCBmdW5jdGlvbihiYXRjaCl7CiAgICBjaGF0RmlsZSA9IHJlYWRfanNvbihwYXN0ZShkYXRhUGF0aCxiYXRjaCwiY2hhdHMuanNvbiIsc2VwPSIvIiksIHNpbXBsaWZ5VmVjdG9yID0gVFJVRSkKICAgIHJldHVybihmbGF0dGVuKGNoYXRGaWxlLCByZWN1cnNpdmUgPSBUUlVFKSkKICB9KQoKYWxsQ2hhdEZpbGVzIDwtIHBseXI6OmxkcGx5KGNoYXRGaWxlcywgZGF0YS5mcmFtZSkKY2hhdEZyZXEgPC0gYWxsQ2hhdEZpbGVzICAlPiUKICBncm91cF9ieShyb3VuZCwgcm9vbSwgYmF0Y2gpICU+JSAKICBkcGx5cjo6c3VtbWFyaXNlKG49bigpKSAlPiUgCiAgZmlsdGVyKG4+MSwgcm91bmQ8PTIpCgojIyBGaWx0ZXIgb24gcm91bmQgPD0yLCBiZWNhdXNlIHJvdW5kIDMgaW4gYWxsIGJ1dCBvbmUgY2FzZSBpcyBvbmx5IGluY2x1ZGVzICJYIGhhcyBsZWZ0IGNoYXQgcm9vbSIgCgojIEhpc3RvZ3JhbSBncm91cGVkIGJ5IHJvdW5kOiAKZyA8LSBnZ3Bsb3QoY2hhdEZyZXEsIGFlcyhuKSkgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNwZWN0cmFsIikKZyArIGdlb21faGlzdG9ncmFtKGFlcyhmaWxsPWZhY3Rvcihyb3VuZCkpLCAKICAgICAgICAgICAgICAgICAgIGJpbnM9NSwgCiAgICAgICAgICAgICAgICAgICBjb2w9ImJsYWNrIiwgCiAgICAgICAgICAgICAgICAgICBzaXplPS4xKSArICAgIyBjaGFuZ2UgbnVtYmVyIG9mIGJpbnMKICBsYWJzKHRpdGxlPSJIaXN0b2dyYW0gb2YgdGhlIG51bWJlciBvZiBjaGF0IGxpbmVzIHBlciB0ZWFtIChpbmNsdWRlcyB0ZWFtcyB3aXRoIG49MSkiLCAKICAgICAgIGZpbGwgPSAiUm91bmQiKSArIAogIHhsYWIobGFiZWw9Ik51bWJlciBvZiBsaW5lcyBmcm9tIGNoYXQgZGF0YSBwZXIgdGVhbSIpICsgCiAgeWxhYihsYWJlbD0iQ291bnQiKSAKc3RhdHMkcm9vbSA8LSB1bmxpc3Qoc3RhdHMkcm9vbSkgCmNoYXRGcmVxU3RhdHMgPC0gcmlnaHRfam9pbih4PWNoYXRGcmVxLCB5PXN0YXRzKQpgYGAKCiMjIENvbmRpdGlvbmFsIHByb2JhYmlsaXRpZXM6IApgYGB7cn0KZ3JvdXBlZFByb3BvcnRpb25GcmFjdHVyZVRyZWF0bWVudCAlPiUgCiAgZ3JvdXBfYnkoY29uZGl0aW9uKSAlPiUgCiAgc3VtbWFyaXNlKG49bigpLCBjb3VudD1jb3VudChmcmFjdHVyZSkpIAoKIyBQKEYzfEYxKSAKcDEgPC0gIDE5IC8gMzQKCiMgUChub3RGM3xGMSkgCnAyIDwtICAxNSAvIDM0CgojIFAoRjN8RjEpCnAzIDwtIDI0IC8gMzQKCiMjIFAobm90RjN8RjEpCnA0IDwtIDEwIC8gMzQKCiAgIyBQcmludCBvdXQgdGhlIHByb2JhYmlsaXRpZXMKcm91bmQoYyhwMSwgcDIsIHAzLCBwNCksIGRpZ2l0cyA9IDIpICAKCgpgYGAKCgoK